/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_box_reduction.h                                                    *
 ****************************************************************************/

/**
 * @file elisa_box_reduction.h
 * @brief Implementation of box-consistency.
 */


#ifndef _ELISA_BOX_REDUCTION_H
#define _ELISA_BOX_REDUCTION_H

#include "elisa_defs.h"
#include "elisa_observer.h"
#include "elisa_reduction.h"
#include "elisa_real_constraint.h"
#include "elisa_interval_test.h"
#include "elisa_interval_form.h"


#ifdef ELISA_PROFILE
#include "elisa_time.h"
#endif


NAMESPACE_ELISA



/**
 * @ingroup Reduction
 * @class BoxReduction
 * @brief Projection operator implementing box-consistency
 */
class BoxReduction : public Reduction
{
public:
	/**
 	 * Constructor
 	 * @param c the constraint to reduce
 	 * @param v the var that the domain must be reduced
 	 * @param cons the factory for IntrevalForm
 	 */
	BoxReduction (RealConstraint *c,
	              RealVarImpl *v,
	              IntervalFormFactory *cons)
	{
		// Data
		Reduction::post(c);
		_test = new RealConstraintRelation(c, cons, v);
		_v = v;
		_c = c;

		// Precision of box-consistency
		_precision = _StaticPrecision;
		/// _precision = v->precision() / 100;

		// Improvement factor
		_improve = _StaticImprove;

		// Listeners for propagation
		VarImplSet::iterator it;
		for (it = _c->beginVar(); it != _c->endVar(); ++it) {
			(*it)->dependsOn(this, DomainReduction);
		}
	}

	/**
 	 * Destructor
 	 */
	~BoxReduction ()
	{
		delete _test;
	}

	/// Base class's virtual methods
	//@{
	double priority() const
	{
		return 50.0;
	}

	bool reductionAlgorithm();
	//@}

	/**
 	 * Set the precision of box-consistency
 	 * @param p the new precision
 	 */
	void setPrecision(double p)
	{
		_precision = p;
	}

	/**
 	 * Set the precision of box-consistency for all further created reductions
 	 * @param p the new precision
 	 */
	static void SetPrecision(double p)
	{
		_StaticPrecision = p;
	}

	/**
 	 * Set the improvement factor
 	 * @param p the new improvement factor
 	 */
	void setImprovement(double p)
	{
		_improve = p;
	}

	/**
 	 * Set the improvement factor
 	 * @param p the new improvement factor
 	 */
	static void SetImprovement(double p)
	{
		_StaticImprove = p;
	}

	string getReductionName() const
	{
		return "Box";
	}

	VariableImpl *getV()
	{
		return _v;
	}

	void print(std::ostream & os, std::string indent, VecConstraints *v) const
	{
		os << "BoxReduction [";
		printConstraints(os, "", v);
		os << "]";
	}

#ifdef ELISA_PROFILE
	/**
 	 * Accumulates the time spent in the reduce operation.
 	 * Only available in profiling mode.
 	 */
	static Clock ClockBox;

	/**
 	 * Counts the number of calls of the reduce operation
 	 * Only available in profiling mode.
 	 */
	static long NumCall;
#endif // ELISA_PROFILE

private:
	RealVarImpl *_v;                // variable whose domain is reduced
	RealConstraint *_c;                   // real constraint
	RealConstraintRelation *_test;            // interval constraint test
	double _precision;             // precision of box-consistency
	static double _StaticPrecision; // default precision
	double _improve;               // improvement factor
	static double _StaticImprove;  // default improvement factor

	// Reduction functions for left and right bounds of _v's domain
	bool reduceLeft(Bound & left)  const;
	bool reduceRight(Bound & right) const;

	/// Copy protection
	BoxReduction & operator=(const BoxReduction & o)
	{
	}
	BoxReduction(const BoxReduction & o) : Reduction(o)
	{
	}
};
END_NAMESPACE_ELISA
#endif // ELISA_BOX_REDUCTION
